﻿using System;
using System.Collections.Generic;
using System.Linq;
using StoCombatLogHUD.Parsing;

namespace StoCombatLogHUD.Statistics
{
	/// <summary>
	/// Provides live statistics for the CombatLog.
	/// </summary>
	public class CombatLogStatistics : IDisposable
	{
		/// <summary>
		/// The combat log parser instance
		/// </summary>
		public CombatLogParser CombatLogParser { get; private set; }

		/// <summary>
		/// Gets or sets the start time stamp.
		/// </summary>
		/// <value>
		/// The start time stamp.
		/// </value>
		public DateTime StartTimeStamp { get; set; }

		/// <summary>
		/// Gets or sets the end time stamp.
		/// </summary>
		/// <value>
		/// The end time stamp.
		/// </value>
		public DateTime EndTimeStamp { get; set; }

		/// <summary>
		/// The internal statistics storage.
		/// </summary>
		private readonly Dictionary<string, PlayerStatistics> statistics = new Dictionary<string, PlayerStatistics>();

		/// <summary>
		/// Gets the statistics.
		/// </summary>
		/// <value>
		/// The statistics.
		/// </value>
		public Dictionary<string, PlayerStatistics> Statistics
		{
			get
			{
				lock (statistics)
				{
					return statistics.ToDictionary(pair => pair.Key, pair => pair.Value);
				}
			}
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="CombatLogStatistics"/> class.
		/// </summary>
		/// <param name="combatLogParserInstance">The combat log parser instance.</param>
		public CombatLogStatistics(CombatLogParser combatLogParserInstance)
		{
			//StartupTimeStamp = DateTime.Now;
			CombatLogParser = combatLogParserInstance;
			CombatLogParser.CombatLogEntriesChanged += UpdateStatistics;
		}

		/// <summary>
		/// Updates the statistics.
		/// </summary>
		/// <param name="sender">The sender.</param>
		/// <param name="args">The <see cref="Parsing.CombatLogParser.CombatLogEntriesChangedEventArgs"/> instance containing the event data.</param>
		private void UpdateStatistics(object sender, CombatLogParser.CombatLogEntriesChangedEventArgs args)
		{
			lock (statistics)
			{
				foreach (var combatLogEntry in args.NewEntries)
				{
					// Update timestamps
					if (StartTimeStamp.Ticks == 0)
						StartTimeStamp = combatLogEntry.Timestamp;
					EndTimeStamp = combatLogEntry.Timestamp;

					// Ignore Non-players
					if (!combatLogEntry.Owner.IsPlayerName())
						continue;

					// Add an additional PlayerStatistics entry for newly detected players
					var statisticsKey = combatLogEntry.Owner.GetActualName();
					if (!statistics.ContainsKey(statisticsKey))
						statistics.Add(statisticsKey, new PlayerStatistics());

					// Update PlayerStatistics
					statistics[statisticsKey].UpdateFromCombatLogEntry(combatLogEntry);
				}
			}
		}

		/// <summary>
		/// Resets the statistics.
		/// </summary>
		public void ResetStatistics()
		{
			lock (statistics)
			{
				StartTimeStamp = new DateTime();
				EndTimeStamp = new DateTime();
				statistics.Clear();
			}
		}

		/// <summary>
		/// Export the statistics to a combatlog file.
		/// </summary>
		public void ExportToCombatLog(string filePath)
		{
			// Nothing to save
			if (StartTimeStamp.Ticks == 0)
				return;

			// Perform the export
			CombatLogParser.ExportCombatLog(filePath, StartTimeStamp);
		}

		#region IDisposable

		/// <summary>
		/// Gets a value indicating whether this instance is disposed.
		/// </summary>
		/// <value>
		/// <c>true</c> if this instance is disposed; otherwise, <c>false</c>.
		/// </value>
		public bool IsDisposed { get; private set; }

		/// <summary>
		/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
		/// </summary>
		public void Dispose()
		{
			if (IsDisposed)
				return;

			IsDisposed = true;
			CombatLogParser.CombatLogEntriesChanged -= UpdateStatistics;
		}

		#endregion
	}
}
